/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package servidorudp;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Date;
import proyectosudp.src.Dto;
import proyectosudp.src.GrupoInvestigacion;
import proyectosudp.src.Proyecto;
import proyectosudp.src.UnidadAcademica;
import proyectosudp.src.Usuario;
import servidorudp.src.Dao;
import servidorudp.src.Log;

/**
 *
 * @author leo
 */
public class ServidorUDP {
    public static void main(String[] args) throws SocketException, IOException, ClassNotFoundException {
        int PUERTO=8050;
        //byte msg[]=new byte[8192];
        //Creamos el socket UDP del servidor en el pueto asociado
        DatagramSocket dgs = new DatagramSocket(PUERTO);
        /**
         * paquete en el que se env�a informaci�n al cliente
         */
        DatagramPacket dgpEnvio;
        /**
         * paquete en el que se recibe el arreglo de bytes que proviene del cliente
         */
        DatagramPacket dgpRecibido;
        Dto dto = new Dto();
        Log log = new Log();
        Character privilegios= null;
        //String mensaje="";
        Dao dao = new Dao();
        //Dto d= new Dto();
        proyectosudp.src.Usuario us = new proyectosudp.src.Usuario();
        proyectosudp.src.Proyecto py = new proyectosudp.src.Proyecto();
        proyectosudp.src.UnidadAcademica un = new proyectosudp.src.UnidadAcademica();
        proyectosudp.src.GrupoInvestigacion gr = new proyectosudp.src.GrupoInvestigacion();
        while (true){
            String respuesta = new String("");
            dto = new Dto();
            //d= new Dto();
            dgpRecibido = new DatagramPacket(new byte [4096],4096);
            //llega un datagrama
            dgs.receive(dgpRecibido);
            dgpEnvio = new DatagramPacket(new byte [4096],4096);

            /**
             * IF para verificar si los datos vienen en un dto o en un usuario.
             * si vienen en un usuario quiere decir que la operación es o crear usuario o modificar usuario,
             * no hace falta ningún mensaje adicional. Dentro del usuario viene todo lo necesario.
             * Así mismo se deben hacer la creación y modificación de las demás entidades.
             * Se debe tener en cuenta que la clase usuario debe ser igual y estar en el mismo paquete
             * tanto en el cliente como en el servidor. Esto mismo deberá ocurrir con las demás entidades.
             */
            byte[] res = dgpRecibido.getData();
            if(desSerializar(res).getClass().getName().equals("proyectosudp.src.Usuario")){
                us=(proyectosudp.src.Usuario)desSerializar(res);
                dao.crearUsuario(us);
                //mensaje="usuarioCreado";
                respuesta="usuarioCreado#;";
            }else if(desSerializar(dgpRecibido.getData()).getClass().getName().equals("proyectosudp.src.Proyecto")){
                py=(proyectosudp.src.Proyecto)desSerializar(dgpRecibido.getData());
                dao.crearProyecto(py);
                //mensaje="proyectoCreado";
                respuesta="proyectoCreado#;";
            }else if(desSerializar(dgpRecibido.getData()).getClass().getName().equals("proyectosudp.src.UnidadAcademica")){
                un=(proyectosudp.src.UnidadAcademica)desSerializar(dgpRecibido.getData());
                dao.crearUnidad(un);
                //mensaje="UnidadCreada";
                //mensaje="UnidadCreada";
                respuesta="UnidadCreada#;";
            }else if(desSerializar(dgpRecibido.getData()).getClass().getName().equals("proyectosudp.src.GrupoInvestigacion")){
                gr=(proyectosudp.src.GrupoInvestigacion)desSerializar(dgpRecibido.getData());
                dao.crearGrupoInv(gr);
                //mensaje="GrupoCreado";
                respuesta="GrupoCreado#;";
            }else{ //la información llega en un objeto DTO
                dto = (Dto)desSerializar(res);
                if(dto.getMensaje().equals("consultaPrivilegios")){ //cuando el caso de uso es consultar privilegios
                    privilegios = new Character(dao.verificarPrivilegios(dto.getUsuario()));
                    if(privilegios.charValue()=='C'||privilegios.charValue()=='E'){
                        log.almacenarLogBD(dto.getUsuario(), "conexion", "aceptada");
                        log.almacenarLogArchivo(dto.getUsuario()+ "|conexion|"+ "aceptada|"+new Date());
                    }else{
                        log.almacenarLogBD(dto.getUsuario(), "conexion", "rechazada");
                        log.almacenarLogArchivo(dto.getUsuario()+ "|conexion|"+ "rechazada|"+new Date());
                    }
                    //mensaje = "usuarioValidado";
                    respuesta="usuarioValidado#"+privilegios+"#;";
                }else if(dto.getMensaje().startsWith("listarUsuarios")){ //para el caso de uso listar usuarios
                    if(dto.getPrivilegio()=='N'){
                        respuesta="listaUsuariosConsultados#N#;";
                        log.almacenarLogBD(dto.getUsuario(), "listado usuarios", "rechazada");
                        log.almacenarLogArchivo(dto.getUsuario()+ "|listado usuarios|"+ "rechazada|"+new Date());
                    }else{
                        ArrayList<Object> lista = dao.listarUsuarios();
                        //d.setListado(lista);
                        String[] str = dto.getMensaje().split("#");
                        int pos = Integer.parseInt(str[1]);
                        Usuario usuario = (Usuario)lista.get(pos);
                        //d.setRespuesta(usuario.getUsuario()+"#"+lista.size()+"#");
                        //System.out.println("respuesta en lista: "  + d.getRespuesta());
                        respuesta="listaUsuariosConsultados#" +usuario.getUsuario()+"#"+lista.size()+"#";
                        //respuesta="listaUsuarios#" +usuario.getUsuario()+"#"+lista.size()+"#";
                        if(pos==lista.size()-1){
                            log.almacenarLogBD(dto.getUsuario(), "listado usuarios", "aceptada");
                            log.almacenarLogArchivo(dto.getUsuario()+ "|listado usuarios|"+ "aceptada|"+new Date());
                        }
                    }
                    //mensaje = "listaUsuarios";
                }else if(dto.getMensaje().startsWith("listarUnidades")){ //para el caso de uso listar unidades
                    ArrayList<Object> lista = dao.listarUnidades();
                    //d.setListado(lista);
                    String[] str = dto.getMensaje().split("#");
                    int pos = Integer.parseInt(str[1]);
                    UnidadAcademica ua = (UnidadAcademica)lista.get(pos);
                    //d.setRespuesta(usuario.getUsuario()+"#"+lista.size()+"#");
                    //System.out.println("respuesta en lista: "  + d.getRespuesta());
                    respuesta="listaUnidadesConsultadas#" +ua.getUnidadAcademica()+"#"+lista.size()+"#";
                    //respuesta="listaUsuarios#" +usuario.getUsuario()+"#"+lista.size()+"#";
                    if(pos==lista.size()-1){
                        log.almacenarLogBD(dto.getUsuario(), "listado unidades", "aceptada");
                        log.almacenarLogArchivo(dto.getUsuario()+ "|listado unidades|"+ "aceptada|"+new Date());
                    }
                }else if(dto.getMensaje().startsWith("listarGruposInv")){ //para el caso de uso listar unidades
                    ArrayList<Object> lista = dao.listarGruposInv();
                    //d.setListado(lista);
                    String[] str = dto.getMensaje().split("#");
                    int pos = Integer.parseInt(str[1]);
                    GrupoInvestigacion gi = (GrupoInvestigacion)lista.get(pos);
                    //d.setRespuesta(usuario.getUsuario()+"#"+lista.size()+"#");
                    //System.out.println("respuesta en lista: "  + d.getRespuesta());
                    respuesta="listaGruposInvConsultados#" +gi.getGrupoInv()+"#"+lista.size()+"#";
                    //respuesta="listaUsuarios#" +usuario.getUsuario()+"#"+lista.size()+"#";
                    if(pos==lista.size()-1){
                        log.almacenarLogBD(dto.getUsuario(), "listado grupos inv", "aceptada");
                        log.almacenarLogArchivo(dto.getUsuario()+ "|listado grupos inv|"+ "aceptada|"+new Date());
                    }
                }else if(dto.getMensaje().startsWith("listarProyectos")){ //para el caso de uso listar unidades
                    ArrayList<Object> lista = dao.listarProyectos();
                    //d.setListado(lista);
                    String[] str = dto.getMensaje().split("#");
                    int pos = Integer.parseInt(str[1]);
                    Proyecto pr = (Proyecto)lista.get(pos);
                    //d.setRespuesta(usuario.getUsuario()+"#"+lista.size()+"#");
                    //System.out.println("respuesta en lista: "  + d.getRespuesta());
                    respuesta="listaProyectosConsultados#" +pr.getProyecto()+"#"+lista.size()+"#";
                    //respuesta="listaUsuarios#" +usuario.getUsuario()+"#"+lista.size()+"#";
                    if(pos==lista.size()-1){
                        log.almacenarLogBD(dto.getUsuario(), "listado proyectos", "aceptada");
                        log.almacenarLogArchivo(dto.getUsuario()+ "|listado proyectos|"+ "aceptada|"+new Date());
                    }
                }else if(dto.getMensaje().startsWith("generarLogRechazada")){ //para generar log de creación de usuario rechazada
                    String[] str = dto.getMensaje().split("#");
                    if(str[1].equals("crearUsuario")){
                        log.almacenarLogBD(dto.getUsuario(), "crear usuario", "rechazada");
                        log.almacenarLogArchivo(dto.getUsuario()+ "|crear usuario|"+ "rechazada|"+new Date());
                        respuesta="creacionUsuarioRechazada#;";
                    }else if(str[1].equals("modificarUsuario")){
                        log.almacenarLogBD(dto.getUsuario(), "modificar usuario", "rechazada");
                        log.almacenarLogArchivo(dto.getUsuario()+ "|modificar usuario|"+ "rechazada|"+new Date());
                        respuesta="creacionUsuarioRechazada#;";
                    }else if(str[1].equals("crearUnidad")){
                        log.almacenarLogBD(dto.getUsuario(), "crear unidad", "rechazada");
                        log.almacenarLogArchivo(dto.getUsuario()+ "|crear unidad|"+ "rechazada|"+new Date());
                        respuesta="creacionUnidadRechazada#;";
                    }else if(str[1].equals("modificarUnidad")){
                        log.almacenarLogBD(dto.getUsuario(), "modificar unidad", "rechazada");
                        log.almacenarLogArchivo(dto.getUsuario()+ "|modificar unidad|"+ "rechazada|"+new Date());
                        respuesta="creacionUnidadRechazada#;";
                    }else if(str[1].equals("crearGrupoInv")){
                        log.almacenarLogBD(dto.getUsuario(), "crear grupo inv", "rechazada");
                        log.almacenarLogArchivo(dto.getUsuario()+ "|crear grupo inv|"+ "rechazada|"+new Date());
                        respuesta="creacionGrupoInvRechazada#;";
                    }else if(str[1].equals("modificarGrupoInv")){
                        log.almacenarLogBD(dto.getUsuario(), "modificar grupo inv", "rechazada");
                        log.almacenarLogArchivo(dto.getUsuario()+ "|modificar grupo inv|"+ "rechazada|"+new Date());
                        respuesta="creacionGrupoInvRechazada#;";
                    }else if(str[1].equals("crearProyecto")){
                        log.almacenarLogBD(dto.getUsuario(), "crear proyecto", "rechazada");
                        log.almacenarLogArchivo(dto.getUsuario()+ "|crear proyecto|"+ "rechazada|"+new Date());
                        respuesta="creacionProyectoRechazada#;";
                    }else if(str[1].equals("modificarProyecto")){
                        log.almacenarLogBD(dto.getUsuario(), "modificar proyecto", "rechazada");
                        log.almacenarLogArchivo(dto.getUsuario()+ "|modificar proyecto|"+ "rechazada|"+new Date());
                        respuesta="creacionProyectoRechazada#;";
                    }
                    //mensaje = "creacionUsuarioRechazada";
                    
                }else if(dto.getMensaje().equals("consultaDatosUsuario")){ //cuando el caso de uso es consultar usuario
                    Usuario  usuario = dao.consultarDatosUsuarios(dto.getUsuario());
                    log.almacenarLogBD(dto.getLog(), "consultaUsuario", "aceptada");
                    log.almacenarLogArchivo(dto.getLog()+ "|consultaUsuario|"+ "aceptada|"+new Date());
                    //d.setUsuarioConsultado(usuario.getUsuario());
                    //mensaje = "usuarioConsultado";
                    if(usuario!=null)
                        respuesta="usuarioConsultado#"+usuario.getUsuario()+"#;";
                    else
                        respuesta="usuarioConsultado#"+"%"+"#;";
                }else if(dto.getMensaje().equals("consultarUnProyecto")){ //cuando el caso de uso es consultar usuario
                    Proyecto  proyecto = dao.consultarDatosProyecto(dto.getDatoConsulta());
                    log.almacenarLogBD(dto.getLog(), "consultaProyecto", "aceptada");
                    log.almacenarLogArchivo(dto.getLog()+ "|consultaProyecto|"+ "aceptada|"+new Date());
                    //d.setProyectoConsultado(proyecto.getProyecto());
                    //mensaje = "proyectoConsultado";
                    if(proyecto!=null)
                        respuesta="proyectoConsultado#"+proyecto.getProyecto()+"#;";
                    else
                        respuesta="proyectoConsultado#"+"%"+"#;";
                }else if(dto.getMensaje().equals("consultarUnidad")){ //cuando el caso de uso es consultar usuario
                    UnidadAcademica  unidad = dao.consultarDatosUnidad(dto.getDatoConsulta());
                    log.almacenarLogBD(dto.getLog(), "consultaUnidad", "aceptada");
                    log.almacenarLogArchivo(dto.getLog()+ "|consultaUnidad|"+ "aceptada|"+new Date());
                    //d.setUnidadConsultada(unidad.getUnidadAcademica());
                    //mensaje = "unidadConsultada";
                    if(unidad!=null)
                        respuesta="unidadConsultada#"+unidad.getUnidadAcademica()+"#;";
                    else
                        respuesta="unidadConsultada#"+"%"+"#;";
                }else if(dto.getMensaje().equals("consultarGrupoInv")){ //cuando el caso de uso es consultar usuario
                    GrupoInvestigacion  grupoInv = dao.consultarDatosGrupoInv(dto.getDatoConsulta());
                    log.almacenarLogBD(dto.getLog(), "consultaGrupoInv", "aceptada");
                    log.almacenarLogArchivo(dto.getLog()+ "|consultaGrupoInv|"+ "aceptada|"+new Date());
                    //d.setGrupoInvConsultado(grupoInv.getGrupoInv());
                    //mensaje = "grupoInvConsultado";
                    if(grupoInv!=null)
                         respuesta="grupoInvConsultado#"+grupoInv.getGrupoInv()+"#;";
                    else
                        respuesta="grupoInvConsultado#"+"%"+"#;";
                   
                }else if(dto.getMensaje().equals("consultaUnidadesAcademicas")){ //para cargar las unidades académicas qu se muestran para el formulario usuario
                    String unidades = dao.consultarUnidades();
                    //d.setUnidadesConsultadas(unidades);
                    //mensaje = "unidadesConsultadas";
                    respuesta="unidadesConsultadas#"+unidades+"#;";
                }
            }
            //serializar(respuesta);
            //msg=empaquetarMensaje(mensaje, privilegios, d.getListado(), d.getUsuarioConsultado(), d.getUnidadesConsultadas(), d.getProyectoConsultado(),d.getUnidadConsultada(),d.getGrupoInvConsultado(),d.getRespuesta());
            responder(serializar(respuesta), dgpRecibido, dgpEnvio, dgs);
       }
    }
    //metodo para convertir a bytes un objeto
    public static byte[] serializar(Object objeto){

        try{
            ByteArrayOutputStream bs= new ByteArrayOutputStream();
            ObjectOutputStream os = new ObjectOutputStream (bs);
            /*if((((Dto)objeto).getUsuarioConsultado()) != null ) { //si lo que se retorna es un usuario
                System.out.println(((Dto)objeto).getUsuarioConsultado());
                os.writeObject("usuarioConsultado#" + ((Dto)objeto).getUsuarioConsultado()); //el mensaje va en el mismo string, separado por un #
            }else if((((Dto)objeto).getUnidadesConsultadas()) != null ) { //si lo que se retorna son unidades académicas
                System.out.println(((Dto)objeto).getUnidadesConsultadas());
                os.writeObject("unidadesConsultadas#" + ((Dto)objeto).getUnidadesConsultadas()); //el mensaje va en el mismo string, separado por un #
            }else if((((Dto)objeto).getRespuesta()) != null ) { //si lo que se retorna son unidades académicas
                System.out.println(((Dto)objeto).getRespuesta());
                os.writeObject("listaUsuariosConsultados#" + ((Dto)objeto).getRespuesta()); //el mensaje va en el mismo string, separado por un #
            }else{
                os.writeObject(objeto);  // this es de tipo DatoUdp
            }*/
            os.writeObject(objeto);  // this es de tipo DatoUdp
            os.flush();
            os.close();
            return  bs.toByteArray(); // devuelve byte[]
            //TODO: validar si este comportamiento es adecuado e implementar el try catch
        }catch(Exception e){
            e.printStackTrace();
        }
        return null;
    }
    /**
     * Este método se encarga de guardar la respuesta del servidor en un arreglo de bytes.
     * se reciben cada uno de los elementos que se deben almacenar en el dto a serializar
     * A medida de que se vayan creando más casos de uso, este método deberá crecer
     */
    public static byte[] empaquetarMensaje(String mensaje, Character privilegios, ArrayList<Object> lista, String usuario, String unidades, String proyecto, String unidad, String grupoInv,String respuesta){
        try {
            Dto d = new Dto();
            d.setMensaje(mensaje);
            if(privilegios!=null){
                d.setPrivilegio(privilegios.charValue());
            }
            if(lista!=null){
                d.setListado(lista);
            }
            if(usuario!=null && !usuario.equals("")){
                d.setUsuarioConsultado(usuario);
            }
            if(respuesta!=null && !respuesta.equals("")){
                d.setRespuesta(respuesta);
                System.out.println("respuesta: " + respuesta);
            }
            if(unidades!=null && !unidades.equals("")){
                d.setUnidadesConsultadas(unidades);
                System.out.println(unidades);
            }
            if(proyecto!=null && !proyecto.equals("")){
                d.setProyectoConsultado(proyecto);
                System.out.println(proyecto);
            }
            if(unidad!=null && !unidad.equals("")){
                d.setUnidadConsultada(unidad);
                System.out.println(unidad);
            }
            if(grupoInv!=null && !grupoInv.equals("")){
                d.setGrupoInvConsultado(grupoInv);
                System.out.println(grupoInv);
            }
            System.out.println("Objeto DTO de respuesta " + d.getMensaje() + d.getPrivilegio() + d.getUsuarioConsultado()
                    + d.getRespuesta() + d.getUnidadesConsultadas() + d.getProyectoConsultado() + d.getUnidadConsultada() + d.getGrupoInvConsultado());
            return serializar(d);
        }catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }
    
    

    /**
     * M�todo encargado de recibir un mensaje que proviene del cliente y
     * desempaquetarlo y convertir lo que venga en su interior en objetos del dominio
     * y en variables que correspondan a instrucciones varias
     *
     * @param msg
     */
    public static void desempaquetarMensaje(byte[] msg){

    }

    

    public static void escucharMensajes(){

    }

    /**
     *
     * @param respuesta
     */
    public static void responder(byte[] respuesta,DatagramPacket dgpRecibido, DatagramPacket dgpEnvio, DatagramSocket dgs) throws IOException{
        dgpEnvio=new DatagramPacket(respuesta,respuesta.length,dgpRecibido.getAddress(),dgpRecibido.getPort());
        dgs.send(dgpEnvio);
    }

    

    //metodo para convertir en un objeto desde bytes
    public static Object desSerializar(byte[] objBytes){
        try{
            ByteArrayInputStream bs= new ByteArrayInputStream(objBytes); // bytes es el byte[]
            ObjectInputStream is = new ObjectInputStream(bs);
            Object objeto = is.readObject();
//            System.out.println("Mensaje objeto recibido: " + ((Dto)objeto).getMensaje());
            is.close();
            return objeto;
        }catch(Exception e){
            e.printStackTrace();
        }
        return null;
        //TODO: validar si este comportamiento es adecuado e implementar el try catch
    }
}
